/*
 *  packetmgr.c
 *
 *  QQ Packet Management
 *
 *  Copyright (C) 2008  Huang Guan
 *
 *  2008-7-12 Created.
 *
 *  Description: This file mainly includes the functions about 
 *  creating/deleting packets, sending/receiving packets
 *
 */

#include <stdlib.h>
#include <string.h>
#include <time.h>
#ifdef _WINDOWS
#include <winsock.h>
#include <wininet.h>
#else
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#endif

#include "qqdef.hpp"

#include "debug.hpp"
#include "qqclient.hpp"
#include "qqpacket.hpp"
#include "qqsocket.hpp"
#include "packetmgr.hpp"
#include "protocol.hpp"
#include "PackageRecvThread.hpp"




qqpacket* packetmgr_new_send( qqclient* qq, int cmd )
{
//	qqpacketmgr* mgr = &qq->packetmgr;
	qqpacket* p=new qqpacket();	
	p->head = 0x02;
	p->tail = 0x03;
	p->command = cmd;
	p->version = qq->version;
	p->seqno = packetmgr_inc_seqno( qq );
	p->buf->pos = 0;
	return p;
}

ushort packetmgr_inc_seqno( qqclient* qq )
{
	QMutexLocker ql(&qq->seqno_lock);
	qq->seqno = rand();
	return qq->seqno;
}

void packetmgr_new_seqno( qqclient* qq )
{
	QMutexLocker ql(&qq->seqno_lock);
	qq->seqno = (rand()&0xF)<<3;
}

void packetmgr_del_packet( qqpacketmgr* mgr, qqpacket* p )
{
	if( p->match ){
		loop_remove( &mgr->sent_loop, p->match );
	}
	delete p;
}

//检查待发送队列。如果有待ack的包，则不发送。
 void check_ready_packets( qqclient* qq )
{
	qqpacketmgr* mgr = &qq->packetmgr;
	if( loop_is_empty(&mgr->ready_loop) )
		return; 
	//if tcp, we send one by one, otherwise send them all
	int count_=0;
	QMutexLocker ql(&mgr->sent_loop.mutex);
	while( mgr->sent_loop.items.empty() )	//good luck, get a packet and send it.
	{
		qqpacket* p =(qqpacket*) loop_pop_from_head( &mgr->ready_loop );
		if( p && p->buf ){
			//remove p from ready packets
			if( p->head!=0x02 || p->tail !=0x03 ){
				DBG("Fatal error: p->command=%x p->head: %x p->tail: %x", p->command, p->head, 
					p->tail );
				delete p;
				return;
			}
			//DBG_QS(QObject::tr("准备发包,cmd=%1,seq=%2,buflen=%3").arg(qqcmdToQString(p->command)).arg(p->seqno).arg(p->buf->len));
			int ret = qqsocket_send( qq->socket, p->buf->data, p->buf->len );
//			DBG("[%d] out packet cmd: %x", p->command );
			if( ret != p->buf->len ){
				DBG("send packet failed. ret(%d)!=p->len(%d)", ret, p->buf->len );
				delete p;
				qqclient_set_process( qq, P_ERROR );
				break;
			}else{
				count_++;
				if( p->need_ack ){
					p->time_alive = time(NULL);
					mgr->sent_loop.items.push_back(p);
					break;
				}else{
					delete p;
				}
			}
		} else break;
	}
	//if(count_!=0) DBG_QS(.arg(count_).arg(mgr->ready_loop.items.size()));
}



/**
 *
 *@param urge true,重发。false。不是重发。
 */
int packetmgr_put_urge( qqclient* qq, qqpacket* p, bool urge )
{
	qqpacketmgr* mgr = &qq->packetmgr;
	p->time_alive = time(NULL);
	p->send_times ++;
	//ok, send now
	if( QThread::currentThread () == mgr->thread_recv  ){
		//recv thread
		loop_push_to_head( &mgr->temp_loop, p );
	}else{
		loop_push_to_tail( &mgr->ready_loop, p );
		check_ready_packets( qq );
	}
	return 0;
}





static int repeat_searcher( const void* p, const void* v )
{
	return ( p == v );
}




int packetmgr_start( qqclient* qq )
{
	qqpacketmgr *mgr = &qq->packetmgr;
	mgr->thread_recv=new PackageRecvThread(qq);	
	mgr->thread_recv->start();
	return 0;
}


void packetmgr_end( qqclient* qq )
{
	//XXX:mgr已经被提前干掉了.
	qqpacketmgr *mgr = &qq->packetmgr;
	mgr->thread_recv->wait(50000);
	loop_cleanup( &mgr->sent_loop );
	loop_cleanup( &mgr->ready_loop );
	loop_cleanup( &mgr->temp_loop );
	DBG("packetmgr_end");
}



